home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
PowerPlant
/
AGA Classes 1.2
/
Utilities
/
LAGAPopupMenu.cp
< prev
next >
Wrap
Text File
|
1996-06-30
|
11KB
|
356 lines
// ===========================================================================
// LAGAPopupMenu.cp
// ===========================================================================
//
// Copyright © 1996 Chrisoft (Christophe ANDRES) All rights reserved.
//
// You may use this source code in any application (commercial, shareware, freeware,
// postcardware, etc), but not remove this notice (no need to acknowledge the use of
// this class in the about box)
// You may not sell this source code in any form. This source code may be placed on
// publicly accessable archive sites and source code disks. It may not be placed on
// profit archive sites and source code disks without the permission of the author,
// Christophe ANDRES.
//
// This source code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// If you make any change or improvement on this class, please send the improved/changed
// version to : chrisoft@calva.net or Christophe ANDRES
// 20, rue Prosper Mérimée
// 67100 STRASBOURG
// FRANCE
//
// ===========================================================================
// LAGAPopupMenu.h <- double-click + Command-D to see class declaration
//
// LAGAPopupMenu is simply a Popup menu class that works in windows with non white backgrounds.
// The standard Popup Menu CDEF erases in white its title, which in turn looks ugly if your
// background is NOT white.
//
// Note:
// This class is called LAGAPopupMenu, because it was conceived to be used in conjunction with
// other “Apple Grayscale Appearance” classes, although it uses only the standard System 7
// Popup Menu CDEF and henceforth has NOT the look described in the AGA document.
//
// Note:
// The use of this class is only necessary IF the Popup Menu you are using uses a title
//
// This class requires AGAColors.cp to be present in your project
//
// Version : 1.2
//
// Change History (most recent first, date in US form : mm/dd/yy):
//
// 06/30/96 ca Public release of version 1.2
// 06/09/96 bp Brad Pettit <bpettit@aimnet.com>
// reimplemented using new StAGAEraseHack, since text alignment of the label
// wasn't always correct for different fonts and label justification.
// 06/05/96 ca Added RegisterClass method to ease registry
// Increased version to 1.2
// 05/17/96 ca Increased version to 1.1
// Replaced UEnvironment::HasFeature(env_SupportsColor) with PaneInColor
// Added change history
// 05/07/96 ca class made available by Christophe ANDRES <chrisoft@calva.net>
// (version 1.0)
//
// To Do:
//
#include "LAGAPopupMenu.h"
#include "AGAColors.h"
// begin <06/09/96 bp>
// Magic: this stack-based class sets up an alternate set of quickdraw procs
// so that we can undo the lame side-effects of the standard pop-up control, which
// ignores the port's background color when drawing itself.
// When it performs an erase on a rectangle that intersects the area that is passed
// to this objects constructor, we replace the background color with the specified
// background color.
// This class should not be created with new(), it should always be instantiated
// on the stack. Nesting of these objects _may_ not do the right thing.
// Possible Improvements: If qdProcs were already installed in this port, call them
// instead of the original function.
// -Contributed by Brad Pettit <bpettit@aimnet.com>
class StAGAEraseHack
{
public:
StAGAEraseHack(LPane *inPane, const Rect& inAGARect, const RGBColor& inAGAColor);
~StAGAEraseHack();
private:
static pascal void RectFunction(GrafVerb verb, Rect *rect);
Boolean mWorking;
GrafPtr mPort;
CQDProcs mProcs;
QDProcs *mOldProcs;
RGBColor mOldColor; // an attempt to support nesting
Rect mOldRect; // an attempt to support nesting
// we _could_ declare our own custom CQDProcs structure that has these
// members at the end. But this is easier, and only 14 bytes versus the extra complexity.
static Rect sOverrideRect;
static RGBColor sOverrideColor;
};
Rect StAGAEraseHack::sOverrideRect;
RGBColor StAGAEraseHack::sOverrideColor;
StAGAEraseHack::StAGAEraseHack (LPane* inPane, const Rect& inAGARect, const RGBColor& inAGAColor)
{
mWorking = ::PaneInColor(inPane); // otherwise we don't need to do anything
if (mWorking)
{
// save the old rectangle in case this is a nested occurrance of this object
mOldRect = sOverrideRect;
sOverrideRect = inAGARect;
// and ditto on the color
mOldColor = sOverrideColor;
sOverrideColor = inAGAColor;
// initialize the procs with the standard quickdraw procs
::SetStdCProcs(&mProcs);
// and replace the rect function with ours
mProcs.rectProc = NewQDRectProc(RectFunction);
::GetPort(&mPort);
// save the original grafProcs
mOldProcs = mPort->grafProcs;
// and install our grafProcs
mPort->grafProcs = (QDProcs*) &mProcs;
}
}
StAGAEraseHack::~StAGAEraseHack ()
{
if(mWorking) // otherwise we didn't do anything
{
// restore the original grafProcs
mPort->grafProcs = (QDProcs*) mOldProcs;
// and free our routine descriptor
DisposeRoutineDescriptor(mProcs.rectProc);
// restore the original color and rectangle in case we were nested.
sOverrideColor = mOldColor;
sOverrideRect = mOldRect;
}
}
// Magic: intercept the rect drawing calls and override the color
// if we're performing an erase
// static
pascal void StAGAEraseHack::RectFunction (GrafVerb verb, Rect *rect)
{
if(verb == kQDGrafVerbErase)
{
Rect scratch;
if(::SectRect(rect, &sOverrideRect, &scratch))
::RGBBackColor(&sOverrideColor);
}
::StdRect(verb, rect); // perform the original quickdraw function
}
// end <06/09/96 bp>
// begin <06/05/96 ca>
void LAGAPopupMenu::RegisterClass ()
{
URegistrar::RegisterClass(LAGAPopupMenu::class_ID, (ClassCreatorFunc)LAGAPopupMenu::CreateAGAPopupMenuStream);
}
// end <06/05/96 ca>
LAGAPopupMenu* LAGAPopupMenu::CreateAGAPopupMenuStream (LStream *inStream)
{
return(new LAGAPopupMenu(inStream));
}
LAGAPopupMenu::LAGAPopupMenu (LStream *inStream) : LStdControl(inStream)
{
Int16 initialMenuItem;
inStream->ReadData(&initialMenuItem, sizeof(Int16));
InitAGAPopupMenu(initialMenuItem);
}
LAGAPopupMenu::LAGAPopupMenu (const SPaneInfo &inPaneInfo, MessageT inValueMessage,
Int16 inTitleOptions, ResIDT inMENUid, Int16 inTitleWidth,
Int16 inPopupVariation, ResIDT inTextTraitsID, Str255 inTitle,
OSType inResTypeMENU, Int16 inInitialMenuItem)
: LStdControl(inPaneInfo, inValueMessage, inTitleOptions, inMENUid, inTitleWidth,
inPopupVariation, inTextTraitsID, inTitle, inResTypeMENU)
{
InitAGAPopupMenu(inInitialMenuItem);
}
void LAGAPopupMenu::DrawSelf()
{
// For some reason, after a Popup Menu moves, the Control Manager
// erases the old location of the Popup. All this happens within
// the Draw1Control() call to draw the Popup at its new location.
// To prevent this erasure, we restrict the clipping region to
// just the current location of the Popup.
#ifdef NOT_DEFINED
Rect frame;
CalcLocalFrameRect(frame);
if (::PaneInColor(this))
{
frame.left += mTitleWidth;
{
StClipRgnState clip;
clip.ClipToIntersection(frame);
LStdControl::DrawSelf();
}
Int16 just = UTextTraits::SetPortTextTraits(mTextTraitsID);
CalcLocalFrameRect(frame);
frame.right = frame.left + mTitleWidth;
ApplyForeAndBackColors();
::EraseRect(&frame);
frame.left += 4;
frame.right -= 4;
FontInfo info;
::GetFontInfo(&info);
frame.top += (((frame.bottom - frame.top) - (info.ascent + info.descent)) / 2) - 1;
Str255 theTitle;
GetDescriptor(theTitle);
{
StClipRgnState clip2;
clip2.ClipToIntersection(frame);
UTextDrawing::DrawWithJustification((Ptr)&theTitle[1], theTitle[0], frame, just);
}
}
else
{
// If we have no color, then we leave everything to the real popup CDEF
StClipRgnState clip;
clip.ClipToIntersection(frame);
LStdControl::DrawSelf();
}
#else
// begin <06/09/96 bp>
StClipRgnState clip;
Rect frame;
CalcLocalFrameRect(frame);
clip.ClipToIntersection(frame);
Rect title;
GetTitleRect(title);
StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
LStdControl::DrawSelf();
// end <06/09/96 bp>
#endif /*NOT_DEFINED*/
}
MenuHandle LAGAPopupMenu::GetMacMenuH ()
{
PopupPrivateDataHandle dataH = (PopupPrivateDataHandle)(**GetMacControl()).contrlData;
return (**dataH).mHandle;
}
// begin <06/09/96 bp>
// overridden because it draws the control as a side-effect
Boolean LAGAPopupMenu::TrackHotSpot (Int16 inHotSpot, Point inPoint)
{
Boolean result = LStdControl::TrackHotSpot(inHotSpot, inPoint);
// redraw the control, since TrackHotSpot left the background white
FocusDraw();
DrawSelf();
return result;
}
// overridden because it may draw the control as a side-effect
void LAGAPopupMenu::SetValue (Int32 inValue)
{
FocusDraw();
Rect title;
GetTitleRect(title);
StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
LStdControl::SetValue(inValue);
}
// overridden because it may draw the control as a side-effect
void LAGAPopupMenu::SetMaxValue (Int32 inValue)
{
FocusDraw();
Rect title;
GetTitleRect(title);
StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
LStdControl::SetMaxValue(inValue);
}
// overridden because it may draw the control as a side-effect
void LAGAPopupMenu::SetMinValue (Int32 inValue)
{
FocusDraw();
Rect title;
GetTitleRect(title);
StAGAEraseHack eraseHack(this, title, gAGAColorArray[2]);
inherited::SetMinValue(inValue);
}
void LAGAPopupMenu::GetTitleRect (Rect& outRect)
{
CalcLocalFrameRect(outRect);
outRect.right = outRect.left + mTitleWidth;
}
// end <06/09/96 bp>
void LAGAPopupMenu::InitAGAPopupMenu (Int16 inInitialMenuItem)
{
mTitleWidth = mMaxValue;
// begin <06/09/96 bp>
#ifdef NOT_DEFINED
// we don't use these. This is an example of how to
// extract the justification and style information for the title
mTitleJust = mValue & 0x000000ff; // low byte stores justification
mTitleStyle = ((mValue & 0x0000ff00) & ~popupTitleNoStyle) >> 8; // second byte stores style
#endif /*NOT_DEFINED*/
// end <06/09/96 bp>
// Popups use the initial values for other purposes. Control Manager
// determines min/max from the size of the Menu. So now we have to
// adjust the value, min, and max stored by LControl.
mValue = ::GetControlValue(mMacControlH);
mMinValue = ::GetControlMinimum(mMacControlH);
mMaxValue = ::GetControlMaximum(mMacControlH);
if (inInitialMenuItem != mValue)
{
::SetControlValue(mMacControlH, inInitialMenuItem);
mValue = ::GetControlValue(mMacControlH);
}
}